package com.qc31.monitorlib.clusters

import android.content.Context
import android.graphics.Color
import android.os.*
import android.util.LruCache
import android.util.TypedValue
import android.view.Gravity
import android.widget.TextView
import com.amap.api.maps.AMap
import com.amap.api.maps.AMapUtils
import com.amap.api.maps.CameraUpdateFactory
import com.amap.api.maps.model.*
import com.qc31.baselib.utils.ScreenUtil
import com.qc31.comlib.map.MarkerSet
import com.qc31.monitorlib.R
import java.util.concurrent.CopyOnWriteArrayList

/**
 * Created by yiyi.qi on 16/10/10.
 * 整体设计采用了两个线程,一个线程用于计算组织聚合数据,一个线程负责处理Marker相关操作
 */
class ClusterOverlay(
    amap: AMap, clusterItems: MutableList<ClusterItem>?,
    clusterSize: Int, context: Context
) : AMap.OnCameraChangeListener, AMap.OnMarkerClickListener {
    private val mAMap: AMap
    private val mContext: Context
    private var mClusterItems: MutableList<ClusterItem>? = null
    private val mClusters: MutableList<Cluster>
    private var mClusterSize: Int
    private var mClusterClickListener: ClusterClickListener? = null
    private var mClusterRender: ClusterRender? = null
    private val mAddMarkers = CopyOnWriteArrayList<Marker>()
    private var mClusterDistance: Double
    private val mLruCache: LruCache<Int, BitmapDescriptor?>
    private val mMarkerHandlerThread = HandlerThread("addMarker")
    private val mSignClusterThread = HandlerThread("calculateCluster")
    private var mMarkerHandler: Handler? = null
    private var mSignClusterHandler: Handler? = null
    private var mPXInMeters: Float
    private var mIsCanceled = false

    private var isShowSpeed = false

    /**
     * 构造函数
     *
     * @param amap
     * @param clusterSize 聚合范围的大小（指点像素单位距离内的点会聚合到一个点显示）
     * @param context
     */
    constructor(amap: AMap, clusterSize: Int, context: Context) : this(
        amap, null, clusterSize, context
    ) {
        isShowSpeed = MarkerSet.mMarkerSet.showSpeed
    }


    /**
     * 设置聚合点的点击事件
     *
     * @param clusterClickListener
     */
    fun setOnClusterClickListener(
        clusterClickListener: ClusterClickListener?
    ) {
        mClusterClickListener = clusterClickListener
    }

    /**
     * 添加一个聚合点
     *
     * @param item
     */
    private fun addClusterItem(item: ClusterItem?) {
        val message = Message.obtain()
        message.what = CALCULATE_SINGLE_CLUSTER
        message.obj = item
        mSignClusterHandler!!.sendMessage(message)
    }

    /**
     * 设置聚合元素的渲染样式，不设置则默认为气泡加数字形式进行渲染
     *
     * @param render
     */
    fun setClusterRenderer(render: ClusterRender) {
        mClusterRender = render
    }

    /**
     * 移除并添加单个车辆图标
     *
     * @param clusterItem
     */
    fun removeSingleMarker(clusterItem: ClusterItem) {
        if (mClusterItems == null) return
        for (item in mClusterItems!!) {
            if (clusterItem.carId == item.carId) {
                mClusterItems?.remove(item)
                break
            }
        }
        addClusterItem(clusterItem)
    }


    /**
     * 移动当前车辆位置
     *
     * @param carId
     */
    fun cameraCar(carId: String) {
        for (item in mClusterItems!!) {
            if (carId == item.carId) {
                mAMap.animateCamera(CameraUpdateFactory.newLatLngZoom(item.position, 18f))
                break
            }
        }
    }

    /**
     * 设置是否聚合
     *
     * @param isCluster
     */
    fun setCluster(isCluster: Boolean) {
        if (isCluster) {
            mClusterSize = ScreenUtil.dp2px(mContext, 30)
            mClusterDistance = (mPXInMeters * mClusterSize).toDouble()
        } else {
            mClusterDistance = 0.0
            mClusterSize = 0
        }
        clearMarkers()
        mAMap.clear()
        assignClusters()
    }

    /** 清除聚合数据和markers */
    fun clearCluster() {
        clearMarkers()
        mClusterItems?.clear()
    }

    /**
     * 添加车辆图标
     *
     * @param items
     */
    fun addClusterItems(items: MutableList<ClusterItem>) {
        clearCluster()
        mClusterItems?.addAll(items)
        assignClusters()
    }

    /** 刷新e */
    fun refresh() {
        assignClusters()
    }

    /** 销毁 */
    fun onDestroy() {
        mIsCanceled = true
        mSignClusterHandler!!.removeCallbacksAndMessages(null)
        mMarkerHandler!!.removeCallbacksAndMessages(null)
        mSignClusterThread.quit()
        mMarkerHandlerThread.quit()
        clearCluster()
        mLruCache.evictAll()
    }

    //初始化Handler
    private fun initThreadHandler() {
        mMarkerHandlerThread.start()
        mSignClusterThread.start()
        mMarkerHandler = MarkerHandler(mMarkerHandlerThread.looper)
        mSignClusterHandler = SignClusterHandler(mSignClusterThread.looper)
    }

    override fun onCameraChange(arg0: CameraPosition) {}
    override fun onCameraChangeFinish(arg0: CameraPosition) {
        mPXInMeters = mAMap.scalePerPixel
        mClusterDistance = (mPXInMeters * mClusterSize).toDouble()
        assignClusters()
    }

    //点击事件
    override fun onMarkerClick(arg0: Marker): Boolean {
        if (mClusterClickListener == null) {
            return true
        }
        val cluster = arg0.getObject() as Cluster?
        if (cluster != null) {
            val count = cluster.clusterCount
            if (count > 1) {
                mClusterClickListener!!.onClick(arg0, cluster.clusterItems)
            } else {
                val clusterItem = cluster.clusterItems[0]
                mClusterClickListener!!.onItemClick(arg0, clusterItem)
            }
            return true
        }
        return false
    }

    /** 将聚合元素添加至地图上 */
    private fun addClusterToMap(clusters: List<Cluster>) {
        clearMarkers()
        for (cluster in clusters) {
            if (mIsCanceled) {
                return
            }
            addSingleClusterToMap(cluster)
        }
    }

    /** 清除Marker */
    private fun clearMarkers() {
        for (marker in mAddMarkers) {
            marker.remove()
        }
        mAddMarkers.clear()
    }

    /**
     * 将单个聚合元素添加至地图显示
     *
     * @param cluster
     */
    private fun addSingleClusterToMap(cluster: Cluster) {
        val latlng = cluster.centerLatLng
        val markerOptions = MarkerOptions()
        if (isShowSpeed) {
            markerOptions.anchor(0.05f, 0.5f)
        } else {
            markerOptions.anchor(0.1f, 0.5f)
        }
        markerOptions.icon(getBitmapDes(cluster)).position(latlng)
        val marker = mAMap.addMarker(markerOptions)
        marker.setObject(cluster)
        cluster.marker = marker
        if (mIsCanceled) {
            return
        }
        mAddMarkers.add(marker)
    }

    /** 聚合计算 */
    private fun calculateClusters() {
        mIsCanceled = false
        mClusters.clear()
        val visibleBounds = mAMap.projection.visibleRegion.latLngBounds
        //耗时
        for (clusterItem in mClusterItems!!) {
            if (mIsCanceled) {
                return
            }
            val latlng = clusterItem.position
            if (visibleBounds.contains(latlng)) {
                var cluster = getCluster(latlng, mClusters)
                if (cluster == null) {
                    cluster = Cluster(latlng)
                    mClusters.add(cluster)
                }
                cluster.addClusterItem(clusterItem)
            }
        }
        //复制一份数据，规避同步
        val clusters: List<Cluster> = ArrayList(mClusters)
        val message = Message.obtain()
        message.what = ADD_CLUSTER_LIST
        message.obj = clusters
        if (mIsCanceled) {
            return
        }
        mMarkerHandler!!.sendMessage(message)
    }

    /** 对点进行聚合 */
    private fun assignClusters() {
        mIsCanceled = true
        mSignClusterHandler!!.removeMessages(CALCULATE_CLUSTER)
        mSignClusterHandler!!.sendEmptyMessage(CALCULATE_CLUSTER)
    }

    /**
     * 在已有的聚合基础上，对添加的单个元素进行聚合
     *
     * @param clusterItem
     */
    private fun calculateSingleCluster(clusterItem: ClusterItem) {
        val visibleBounds = mAMap.projection.visibleRegion.latLngBounds
        val latlng = clusterItem.position
        if (!visibleBounds.contains(latlng)) {
            return
        }
        var cluster = getCluster(latlng, mClusters)
        if (cluster != null) {
            cluster.removeClusterItem(clusterItem)
            cluster.addClusterItem(clusterItem)
            val message = Message.obtain()
            message.what = UPDATE_SINGLE_CLUSTER
            message.obj = cluster
            mMarkerHandler!!.removeMessages(UPDATE_SINGLE_CLUSTER)
            mMarkerHandler!!.sendMessageDelayed(message, 5)
        } else {
            cluster = Cluster(latlng)
            mClusters.add(cluster)
            cluster.addClusterItem(clusterItem)
            val message = Message.obtain()
            message.what = ADD_SINGLE_CLUSTER
            message.obj = cluster
            mMarkerHandler!!.sendMessage(message)
        }
    }

    /**
     * 根据一个点获取是否可以依附的聚合点，没有则返回null
     *
     * @param latLng
     * @return
     */
    private fun getCluster(latLng: LatLng?, clusters: List<Cluster>): Cluster? {
        for (cluster in clusters) {
            val clusterCenterPoint = cluster.centerLatLng
            val distance = AMapUtils.calculateLineDistance(latLng, clusterCenterPoint).toDouble()
            if (distance < mClusterDistance && mAMap.cameraPosition.zoom < 19) {
                return cluster
            }
        }
        return null
    }

    /** 获取每个聚合点的绘制样式 */
    private fun getBitmapDes(cluster: Cluster): BitmapDescriptor? {
        val num = cluster.clusterCount
        var bitmapDescriptor: BitmapDescriptor?
        if (num > 1) {
            bitmapDescriptor = mLruCache.get(num)
            if (bitmapDescriptor == null) {
                val textView = TextView(mContext)
                val tile = num.toString()
                textView.text = tile
                textView.gravity = Gravity.CENTER
                textView.setTextColor(Color.WHITE)
                textView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 12f)
                if (mClusterRender != null) {
                    textView.background = mClusterRender!!.getDrawAble(num)
                }
                bitmapDescriptor = BitmapDescriptorFactory.fromView(textView)
                mLruCache.put(num, bitmapDescriptor)
            }
        } else {
            bitmapDescriptor =
                if (mClusterRender != null) {
                    mClusterRender!!.getBitmapDesc(cluster.clusterItems[0])
                } else {
                    BitmapDescriptorFactory.fromResource(R.mipmap.ic_car_location_no)
                }
        }
        return bitmapDescriptor
    }

    /** 更新已加入地图聚合点的样式 */
    private fun updateCluster(cluster: Cluster) {
        val marker = cluster.marker
        marker!!.setIcon(getBitmapDes(cluster))
    }

    //-----------------------辅助内部类用---------------------------------------------
    /** 处理market添加，更新等操作 */
    internal inner class MarkerHandler(looper: Looper?) : Handler(looper!!) {
        override fun handleMessage(message: Message) {
            when (message.what) {
                ADD_CLUSTER_LIST -> {
                    val clusters = message.obj as List<Cluster>
                    addClusterToMap(clusters)
                }
                ADD_SINGLE_CLUSTER -> {
                    val cluster = message.obj as Cluster
                    addSingleClusterToMap(cluster)
                }
                UPDATE_SINGLE_CLUSTER -> {
                    val updateCluster = message.obj as Cluster
                    updateCluster(updateCluster)
                }
            }
        }


    }

    /**
     * ***********************************聚合状态*************************************************
     */
    companion object {
        const val ADD_CLUSTER_LIST = 0
        const val ADD_SINGLE_CLUSTER = 1
        const val UPDATE_SINGLE_CLUSTER = 2

        const val CALCULATE_CLUSTER = 0
        const val CALCULATE_SINGLE_CLUSTER = 1
    }

    /** 处理聚合点算法线程 */
    internal inner class SignClusterHandler(looper: Looper?) : Handler(looper!!) {
        override fun handleMessage(message: Message) {
            when (message.what) {
                CALCULATE_CLUSTER -> calculateClusters()
                CALCULATE_SINGLE_CLUSTER -> {
                    val item = message.obj as ClusterItem
                    mClusterItems!!.add(item)
                    calculateSingleCluster(item)
                }
            }
        }
    }


    /**
     * 构造函数,批量添加聚合元素时,调用此构造函数
     *
     * @param amap
     * @param clusterItems 聚合元素
     * @param clusterSize
     * @param context
     */
    init {
        //默认最多会缓存80张图片作为聚合显示元素图片,根据自己显示需求和app使用内存情况,可以修改数量
        mLruCache = object : LruCache<Int, BitmapDescriptor?>(150) {
            override fun entryRemoved(
                evicted: Boolean, key: Int?,
                oldValue: BitmapDescriptor?, newValue: BitmapDescriptor?
            ) {
                oldValue?.recycle()
            }
        }
        mClusterItems = clusterItems ?: ArrayList()
        mContext = context
        mClusters = ArrayList()
        mAMap = amap
        mClusterSize = clusterSize
        mPXInMeters = mAMap.scalePerPixel
        mClusterDistance = (mPXInMeters * mClusterSize).toDouble()
        amap.setOnCameraChangeListener(this)
        amap.setOnMarkerClickListener(this)
        initThreadHandler()
        assignClusters()
    }
}